package com.cy.pj.common.config;
import java.util.LinkedHashMap;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/** @Configuration 注解描述的类为spring框架中的一个配置类  */
@Configuration
public class SpringShiroConfig {
	/**
	    *  配置会话管理对象(Session管理器)，在Shiro框架的应用中，用户登陆成功以后
	       默认会将用户信息存储到session(服务端的一个对象)。
	 */
	@Bean
	public SessionManager sessionManager() {
		DefaultWebSessionManager sessionManager=new DefaultWebSessionManager();
		//设置session生命周期(默认为30分钟)
		sessionManager.setGlobalSessionTimeout(60*60*1000);
		return sessionManager;
	}
	/**
	 * 配置记住我管理器对象，此对象可以通过cookie对象存储账户信息，并将此信息
	 * 写到客户端，下次客户端可以访问服务端时，可以携带cookie中的信息进行自动
	 * 认证。
	 */
	@Bean
	public RememberMeManager rememberMeManager() {
		CookieRememberMeManager cManager=new CookieRememberMeManager();
		SimpleCookie cookie=new SimpleCookie("rememberMe");
		cookie.setMaxAge(7*24*60*60);
		cManager.setCookie(cookie);
		
		//设置加密解密密钥(假如服务器重启以后，还是需要重新登陆，将下面的语句注释掉)
		//注意:
		//1)密钥的选择16位的一个字符串
		//2)密钥的复杂度越高，加密以后的内容就越安全。
		//cManager.setCipherKey("abcd12345678qwer".getBytes());
		return cManager;
	}
	/**
	 * 配置shiro框架的缓存管理器对象(这个对象不是缓存对象，是管理缓存的一个对象)
	   基于此配置可以在Shiro框架内部初始化一个Cache对象，此Cache对象可以存储用户的权限
	   信息，当用户访问一个授权才可以访问的方法时，我们需要从数据库获取用户权限信息，
	   然后还可以将用户的这个权限信息缓存起来，下次需要时从缓存获取即可。
	 * @return
	 */
	@Bean
	public CacheManager shiroCacheManager() {
		return new MemoryConstrainedCacheManager();
	}
    /**
     * SecurityManager 对象shiro框架的核心。
     * @Bean 通常会配置@Configuration注解进行使用，其它特点：
     * 1)此注解描述方法会交给spring管理
     * 2)@Bean注解没有指定其value属性的值，则bean的名字默认为方法名
     * @return
     */
	//@Bean(value="sManager")
	@Bean
	public SecurityManager securityManager(Realm realm,
			CacheManager cacheManager,
			RememberMeManager rememberManager,
			SessionManager sessionManager) {
		DefaultWebSecurityManager sManager=new DefaultWebSecurityManager();
		sManager.setRealm(realm);
		sManager.setCacheManager(cacheManager);
		sManager.setRememberMeManager(rememberManager);
		sManager.setSessionManager(sessionManager);
		return sManager;
	}
	/**
	 * Spring容器在管理ShiroFilterFactoryBean对象，
	 *    会基于ShiroFilterFactoryBean对象, 创建过滤器工厂对象（SpringShiroFilter），
	 *    然后通过过滤器工厂创建过滤器(filter)对象,最后通过Filter对请求数据进行过滤，
	 *    例如调用securityManager的方法判定此请求是否已经过认证，假如没有经过认证
	 *    则跳转到登陆页面进行认证即可。
	 * @param securityManager
	 * @return
	 */
	@Bean
	public ShiroFilterFactoryBean shiroFilterFactory(SecurityManager securityManager) {
		ShiroFilterFactoryBean fBean=new ShiroFilterFactoryBean();
		fBean.setSecurityManager(securityManager);
		//设置需要进行认证的登陆页面
		fBean.setLoginUrl("/doLoginUI");
		//设置过滤规则(有顺序，允许匿名访问的放在上面)
		LinkedHashMap<String,String> filterMap=new LinkedHashMap<>();
		filterMap.put("/bower_components/**","anon");//anno为shiro框架定义，会对应一个过滤器对象，这里表示允许匿名访问
		filterMap.put("/build/**","anon");
		filterMap.put("/dist/**","anon");
		filterMap.put("/plugins/**","anon");
		filterMap.put("/user/doLogin", "anon");//登陆操作允许匿名访问
		filterMap.put("/doLogout", "logout");//logout为登出操作，此操作执行时会进入登陆页面
		//filterMap.put("/**", "authc");//authc为设置需要认证访问的资源
		filterMap.put("/**", "user");//user表示可以通过用户端提交的cookie信息进行认证
		fBean.setFilterChainDefinitionMap(filterMap);
		return fBean;
	}
	/**
	   *  配置Advisor对象，此对象内容会关联切入点和相关通知
	 * @param securityManager
	 * @return
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor 
	authorizationAttributeSourceAdvisor (
		    		    SecurityManager securityManager) {
	AuthorizationAttributeSourceAdvisor advisor=//顾问对象
					new AuthorizationAttributeSourceAdvisor();
	advisor.setSecurityManager(securityManager);
		return advisor;
	}

}







